home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 051-075 / scopedisk73 / newsetfont / setfont.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  20KB  |  544 lines

  1. /* ======================================================================= */
  2.  
  3. /* SetFont 2.0    -
  4.  
  5.         by Dave Haynie (Hazy)
  6.             CIS:     76703,2047
  7.             Usenet:    {allegra,caip,ihnp4}!cbmvax!daveh
  8.             Drink:    Guiness
  9.  
  10.    BUSINESS (MUNDANE, BUT IMPORTANT):
  11.  
  12.     This program is written by me, Dave Haynie, as mentioned above.
  13.    I have, however, placed it in the PUBLIC DOMAIN.  That, of course, means
  14.    that you can do (almost) absolutely anything with it.  You may hack it
  15.    to bits, include it with YOUR product, sell it, GIVE IT AWAY, or anything
  16.    else you like.  Of course, since anyone else can also give it away, it
  17.    would be foolish to stick your name on it and try to sell it.  I really
  18.    would like everyone to give it away, nicely, without being mean about it.
  19.    If you want to use it with your product, do that too, new products for
  20.    the Amiga are generally a good thing for the entire Amiga community.  You
  21.    can take bit and pieces and use them in your own programs, or the whole
  22.    thing for that matter.  And if you really want to have fun, you can even
  23.    IMPROVE this program, as its far from perfect, and give YOUR version 
  24.    away too, if you're so inclined.  That's about it for the (mundane)
  25.    business section, let's get on to the (interesting) notes section.
  26.  
  27.    ABOUT IT:
  28.  
  29.     This program is designed to allow you to set the font of a console
  30.    window (or really, a general WorkBench window) to any font, ROM or disk
  31.    based, that you have in mind.  This works much better than the first
  32.    version, in that it allows a greater variety of things to be changed
  33.    in the WorkBench.  What, you say, a VARIETY of things?  Well, lemme
  34.    explain....
  35.  
  36.        First off, something about fonts.  Amiga fonts all over the place
  37.    default to one of two ROM fonts, as specified in Preferences.  A ROM font
  38.    is just a font that happens to stored in with the KickStart code, instead
  39.    of out on a disk.  Since anything ever running on any Amiga can get to 
  40.    these fonts, they're used very heavily, perhaps too much.  If you've 
  41.    ever used the NotePad, however, you will probably have used some other
  42.    fonts.  These fonts are available on disk, and in fact, you can use
  43.    FontEd to create a variety of disk fonts for your own use.
  44.  
  45.    Whether disk or ROM, most programs use the Amiga's font management
  46.    utilities, which are part of the KickStart based graphics library.  But
  47.    very few folks just look at the graphics library.  Most everyone looks 
  48.    at Intuition.  Intuition manages things like screens and windows, and
  49.    you can write things to both screens and windows.  And, perhaps not
  50.    coincidentally, both screens and windows have some idea of what font they
  51.    should use, providing they've been given no special directions toward
  52.    using some other fonts.  The screen stores a pointer to a critter called
  53.    a "TextAttr", which is essentially a DESCRIPTOR for a font.  A TextAttr
  54.    contains the name of the font, the point size of the font, and a little
  55.    more information related to the font.  Both screens and windows also
  56.    contains a graphics structure, called a RastPort, which points to the
  57.    memory used to store the displayed memory.  The RastPort sports a pointer
  58.    to a different critter, the "TextFont".  The is the actual font, which is
  59.    the result of passing a TextAttr to one of the font opening functions.
  60.  
  61.        In this version I allow you to change the screen's font information,
  62.    like before, but I also know a bit more about the console window now.
  63.    When I open a window within a screen, such as the WorkBench screen, 
  64.    it's RastPort gets its default font from the screen's TextAttr font 
  65.    descriptor.  If this window is going to be a console window, it will
  66.    built a ConUnit, which has its own idea of the current font, based on
  67.    the window.  I can use the ROM Kernal SetFont() call to change the
  68.    font of the Window's RastPort.  Then I send an "<ESC>c" to the console
  69.    which will reinitialize the ConUnit from the window (and also clear
  70.    the screen....oh well).
  71.  
  72.     I need pointers to the window and screen to do this.  Since the 
  73.    Window structure contains a pointer to its screen, my goal is to find
  74.    the window associated with the calling console.  The best way I've found
  75.    for this is by setting up the current console as an I/O item, then
  76.    calling the DOS Info() function, which will return a pointer to the
  77.    console's window.  From this window I can get a the screen pointer and
  78.    the window's RastPort, so the fonts can be put in place.  When the
  79.    Screen's TextAttr is changed, I only change the values of that font
  80.    descriptor that the user's asked me to change.  Occasionally, this can
  81.    result in a few bytes of unreclaimed memory, as in font names:  I have no
  82.    idea how much memory is reserved in the screen's TextAttr structure on
  83.    startup.  I use the SetFont() function to set the window's or screen's
  84.    RastPort fonts.
  85.  
  86.     There are a few problems with my scheme.  First of all, many 
  87.    programs are written to support only the topaz 8 (80 column) font.  If 
  88.    you're a 60 column user, you've probably experienced this before.  Its
  89.    not a problem with the Amiga as a whole, since most of the system will
  90.    adjust itself.  But it may be a problem with programs that have a fixed
  91.    idea of what a font should look like.  Most 80 column fonts work with
  92.    most applications, and an 80 column 8x8 font will work just about
  93.    everywhere.  Some programs, like CLI for instance, have trouble with
  94.    proportionally-spaced fonts.  The best thing to to is try out the font
  95.    you like.  One final problem is that some applications ask the
  96.    WorkBench screen to close when they start up.  It'll close if there's
  97.    nothing else open on it, but when it re-opens, it'll restart with the
  98.    Preferences-selected font, not the SetFont selected font.  Of course,
  99.    preferences doesn't support arbitrary fonts (which is why this program is
  100.    even necessary).  Oh well, maybe in 1.3?  The solution to this is to 
  101.    always keep at least one window open, so that WorkBench will never be
  102.    closed on you.
  103. */
  104.  
  105. /* ======================================================================= */
  106.  
  107. /*    Modifications -
  108.  
  109.         by Keith Young,  DAS Member (Devil's Advocate Software)
  110.             "We do Neat/Dangerous things... so you don't have to"
  111.             CIS: 73170,307
  112.  
  113.      First off, thanks to Dave Haynie (Hazy) for supplying this little
  114.     dittie.  In my never-ending quest to learn something new every day,
  115.     I've discovered a few things about how the system handles fonts and
  116.     made a few changes to SetFont that reflect these findings.
  117.  
  118.      Most of the changes I've made have a /* ky /* in front of the change
  119.     as well as comments about them, so I won't repeat myself up here :).
  120.     The other changes that aren't marked are mostly casts to get the code
  121.     to compile cleanly with Manx and 16 bit ints. To compile/link with
  122.     Manx:    1> cc setfont
  123.             1> ln setfont -lc
  124.  
  125.      There is still one place (font pointer) in the system that I have
  126.     not looked into completely... and that is GfxBase->DefaultFont.
  127.     According to the DevCon notes, this is updated anytime SetPrefs()
  128.     is called, but I'm not yet sure of it's significance.  Whoops...
  129.     make that 2 places... IntuitionBase->Preferences->FontHeight is
  130.     the other... not sure what significance that has either (in the
  131.     grand scheme of things)
  132.  
  133.         Cheers,
  134.                 Keith
  135.  
  136.     p.s.  Keep in mind that this program pokes at INTUITIONPRIVATE
  137.         pointers, and so is not guarranteed to work with future
  138.         versions of the OS.
  139.  
  140. */
  141.  
  142. #include <exec/types.h>
  143. #include <exec/io.h>
  144. #include <exec/ports.h>
  145. #include <exec/memory.h>
  146. #include <graphics/gfxbase.h>
  147. #include <graphics/text.h>
  148. #include <graphics/rastport.h>
  149. #include <libraries/diskfont.h>
  150. #include <libraries/dos.h>
  151. #include <libraries/dosextens.h>
  152. #include <libraries/diskfont.h>
  153. #include <intuition/intuitionbase.h>
  154. #include <stdio.h>
  155.  
  156. #include <functions.h>  /* ky */
  157.  
  158. /* ========================================================================= */
  159.  
  160. /* External things */
  161.  
  162. /* ky */  /* these are in Manx's "functions.h"  header file
  163. extern struct Library *OpenLibrary();
  164. extern struct TextFont *OpenFont();
  165. extern struct TextFont *OpenDiskFont();
  166. extern struct Window *OpenWindow();
  167. */
  168.  
  169. extern char *strcat();
  170. extern char *strcpy();
  171. extern long strlen();
  172.  
  173. /* ========================================================================= */
  174.  
  175. /* Global variables */
  176.  
  177. struct GfxBase *GfxBase = NULL;
  178. struct Library *DiskfontBase = NULL;
  179. struct IntuitionBase *IntuitionBase = NULL;
  180.  
  181. struct MsgPort portblk = { 
  182.     { 0, 0, NT_MSGPORT, 0, 0}, 0, -1, 0, 
  183.     {(struct Node *)&portblk.mp_MsgList.lh_Tail, 0, (struct Node *)&portblk.mp_MsgList.lh_Head, 0, 0} 
  184. };
  185.  
  186. struct MsgPort *port = &portblk;
  187.  
  188. struct IOStdReq reqblk = { 
  189.     {
  190.     {0, 0, 0, 0, 0},
  191.     &portblk, 0    }
  192.     , 0
  193. }; 
  194. struct IOStdReq *request = &reqblk;
  195.  
  196. struct Window *window = NULL;
  197. struct Screen *screen = NULL;
  198.  
  199. /* ========================================================================= */ 
  200.  
  201. /* This section contains startup and shutdown functions. */
  202.  
  203. /* This function opens the required Amiga libraries, devices, and other
  204.    good stuff.  It returns TRUE if successful.  Graphics, Intuition, and
  205.    DiskFont libraries are opened. The console device is opened and the 
  206.    I/O request message port is initialized.  I also do a check to make sure
  207.    that the associated Task is really a Process.  This is absolutely 
  208.    necessary, as some of the functions that I'll be using later are DOS
  209.    functions, which require Processes, not Tasks.  */
  210.  
  211. BOOL OpenUp()
  212. {
  213.     /* The Libraries */
  214.  
  215.     if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == NULL)
  216.         return FALSE;
  217.     if ((DiskfontBase = OpenLibrary("diskfont.library",0L)) == NULL)
  218.         return FALSE;
  219.     if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == NULL)
  220.         return FALSE;
  221.  
  222.     /* The Devices */
  223.  
  224.     if ((OpenDevice("console.device", -1L, request, 0L)) != 0L)
  225.         return FALSE;
  226.     if ((port->mp_SigBit = AllocSignal(-1L)) < 0)
  227.         return FALSE;
  228.     port->mp_SigTask = (struct Task *) FindTask((char *) NULL); 
  229.     if (port->mp_SigTask->tc_Node.ln_Type != NT_PROCESS)
  230.         return FALSE;
  231.     return TRUE;
  232. }
  233.  
  234. /* This function frees up dynamically opened things, like the devices
  235.    and the libraries, opened above. */
  236.  
  237. void ShutDown()
  238.     if (request->io_Device != NULL) { 
  239.         if (port->mp_SigBit != -1) FreeSignal((long)port->mp_SigBit); 
  240.         CloseDevice(request); 
  241.     } 
  242.     if (IntuitionBase != NULL) CloseLibrary(IntuitionBase); 
  243.     if (DiskfontBase != NULL) CloseLibrary(DiskfontBase);
  244.     if (GfxBase != NULL) CloseLibrary(GfxBase);
  245.  
  246. /* ========================================================================= */
  247.  
  248. /* Attribute based functions. */
  249.  
  250. /* This function allocates space for the given font descriptor, converting
  251.    the point size into a numeric form at the same time. */
  252.  
  253. struct TextAttr *AllocAttr(fontname, pointname)
  254. char *fontname, *pointname;
  255. {
  256.     short point;
  257.     char *str;
  258.     struct TextAttr *attr = NULL;
  259.  
  260.     attr = (struct TextAttr *) AllocMem((long)sizeof(*attr),0L);
  261.  
  262.     if (pointname == NULL)
  263.         point = 8;
  264.     else
  265.         point = atoi(pointname);
  266.  
  267.     str = (char *) AllocMem((long)(strlen(fontname)+6),0L);
  268.     strcpy(str,fontname);
  269.     strcat(str,".font");
  270.     attr->ta_Name = (STRPTR) str;
  271.     attr->ta_YSize = point;
  272.     attr->ta_Style = 0;
  273.     attr->ta_Flags = 0;
  274.     return attr;
  275. }
  276.  
  277. /* This function frees a TextAttr allocated with AllocAttr(). */
  278.  
  279. void FreeAttr(attr)
  280. struct TextAttr *attr;
  281. {
  282.     if (attr == NULL)
  283.         return;
  284.     FreeMem(attr->ta_Name, (long)strlen(attr->ta_Name));
  285.     FreeMem(attr,(long)sizeof(*attr));
  286. }
  287. /* ========================================================================= */
  288.  
  289. /* This function allocates a packet and associated info block.  It returns
  290.    a pointer to this packet if successful, NULL otherwise. */
  291.  
  292. struct StandardPacket *AllocInfoPacket()
  293. {
  294.     struct StandardPacket *pac = NULL;
  295.     struct InfoData *inf = NULL;
  296.  
  297.     pac = (struct StandardPacket *) AllocMem((long)sizeof(*pac), MEMF_CLEAR);
  298.     if (pac == NULL)
  299.         return NULL;
  300.     inf = (struct InfoData *) AllocMem((long)sizeof(*inf), MEMF_CLEAR);
  301.     if (inf == NULL) {
  302.         FreeMem(pac,(long)sizeof(*pac));
  303.         return NULL;
  304.     }
  305.     pac->sp_Msg.mn_Node.ln_Name = (char *) &(pac->sp_Pkt); 
  306.     pac->sp_Pkt.dp_Link = &(pac->sp_Msg); 
  307.     pac->sp_Pkt.dp_BufAddr = ((ULONG) inf) >> 2; 
  308.     pac->sp_Pkt.dp_Type = ACTION_DISK_INFO; 
  309.  
  310.     return pac;
  311. }
  312.  
  313. /* ========================================================================= */
  314.  
  315. /* This function gets the Window pointer for the current console.  It 
  316.    takes the message port for the console.  It uses the fact that the I/O
  317.    device's message port points to the process associated with this CLI.  
  318.    This process needs a console window, and it should have a pointer to a
  319.    message port for this purpose.  We use DOS packets to request an
  320.    InfoData block on this console window.  The window pointer is passed 
  321.    back as the volume name of the console.  We're getting into DOS, so look
  322.    out for BCPL pointers and longword alignment! */
  323.  
  324. struct Window *GetConsoleWindow(port)
  325. struct MsgPort *port;
  326. {
  327.     struct MsgPort *cp;             /* Console port */
  328.     struct InfoData *inf;        /* Packet data block */
  329.     struct StandardPacket *pac = NULL;   /* Packet for DOS request */
  330.     struct Window *w = NULL;        /* Resulting Window */
  331.  
  332.     cp = (struct MsgPort *)((struct Process *)port->mp_SigTask)->pr_ConsoleTask; 
  333.     if (cp == 0)
  334.         return NULL;
  335.  
  336.     if ((pac = AllocInfoPacket()) == NULL)
  337.         return NULL;
  338.     pac->sp_Pkt.dp_Port = port; 
  339.     inf = (struct InfoData *) (((ULONG) pac->sp_Pkt.dp_BufAddr) << 2);
  340.     PutMsg(cp, pac); 
  341.     WaitPort(port); 
  342.     w = (struct Window *) inf->id_VolumeNode;
  343.     FreeMem(inf, (long)sizeof(*inf));
  344.     FreeMem(pac, (long)sizeof(*pac));
  345.  
  346.     return w;
  347. }
  348.  
  349. /* ========================================================================= */
  350.  
  351. /* This function tries to get a requested font from an attribute descriptor;
  352.    it returns FALSE if the font doesn't exist. */
  353.  
  354. struct TextFont *GetFont(attr)
  355. struct TextAttr *attr;
  356. {
  357.     struct TextFont *font;
  358.  
  359.     if ((font = OpenDiskFont(attr)) != NULL)
  360.         return font;
  361.  
  362. /* ky */
  363. /* OpenDiskFont() will use an in-memory font if it exists... */
  364. /* so the following call should not be needed */
  365. /*    if ((font = OpenFont(attr)) != NULL)
  366.         return font; */
  367.  
  368.     return NULL;
  369. }
  370.  
  371. /* ========================================================================= */
  372.  
  373. /* The main function */
  374.  
  375. main(argc, argv) 
  376. int argc; 
  377. char *argv[]; 
  378.     short i;
  379.     BOOL printmode = FALSE;
  380.     BOOL mode_screen = FALSE;
  381.     BOOL mode_title = FALSE;
  382.     BOOL mode_window = FALSE;
  383.     struct TextAttr *attr = NULL;
  384.     struct TextFont *newfont, *oldfont;
  385.  
  386.     /* Automatic help command */
  387.  
  388.     if (argc == 1)
  389.         printmode = TRUE;
  390.     else if (argv[1][0] == '?') {
  391.         printf("SetFont 2.0 by Dave Haynie; mods by Keith Young\n\n");
  392.         printf("Usage: SetFont [fontname [point [place]]], where\n\n");
  393.         printf("  \2331mfontname\2330m  is the font's name (e.g. \"topaz\")\n");
  394.         printf("  \2331mpoint\2330m     is the point size (default is 8)\n");
  395.         printf("  \2331mplace\2330m     pick the place, one or more of:\n");
  396.         printf("    \2331mSCREEN\2330m    set the screen font only\n");
  397.         printf("    \2331mTITLES\2330m    set the screen titles only\n");
  398.         printf("    \2331mWINDOW\2330m    set the window's font only\n\n");
  399.         printf("If no \2331mplace\2330m switch is given, everything is set.\n");
  400.         exit(10);
  401.     }
  402.  
  403.     /* Process the command-line arguments, AmigaDOS style. */
  404.  
  405.     for (i=3; i<argc; i++) {
  406.         if (argv[i][0] == 'T' || argv[i][0] == 't')
  407.             mode_title = TRUE;
  408.         else if (argv[i][0] == 'S' || argv[i][0] == 's')
  409.             mode_screen = TRUE;
  410.         else if (argv[i][0] == 'W' || argv[i][0] == 'w')
  411.             mode_window = TRUE;
  412.     }
  413.     if (!mode_title && !mode_screen && !mode_window)
  414.         mode_title = mode_screen = mode_window = TRUE;
  415.  
  416.     /* First all, we've got to open all the good stuff. */
  417.  
  418.     if (!OpenUp() || (window=GetConsoleWindow(port)) == NULL) {
  419.         ShutDown();
  420.         exit(10);
  421.     }
  422.  
  423.     /* Process the informational print mode, real simple */
  424.  
  425.     if (printmode) {
  426.         printf("SetFont 2.0 by Dave Haynie; mods by Keith Young\n\n");
  427.         attr = window->WScreen->Font;
  428.         printf("Screen Font: %s (%ld) ", attr->ta_Name, attr->ta_YSize);
  429.         printf("Style %ld, Flags %ld\n", attr->ta_Style, attr->ta_Flags);
  430.         ShutDown();
  431.         exit(0);
  432.     }
  433.  
  434.     /* Get the attribute and font, where available. */
  435.  
  436.     attr = AllocAttr(argv[1], argv[2]);
  437.     if ((newfont = GetFont(attr)) == NULL) {
  438.         printf("Error: Font not found\n");
  439.         FreeAttr(attr);
  440.         ShutDown(); 
  441.         exit(10);
  442.     }
  443.  
  444.     /* Here's where the various options are processed individually. */
  445.  
  446.     /* The screen titling  font is changed via a SetFont() call to the 
  447.           screen's RastPort.  */
  448.  
  449.     if (mode_title) {
  450.         oldfont = window->WScreen->RastPort.Font;
  451.         if( SetFont(&(window->WScreen->RastPort),newfont) ) {
  452.  
  453. /* ky */ /* the screen's BarLayer->rp also needs to be SetFont'd so
  454.             that the title-bar is displayed correctly... note that
  455.             Intuition (currently) also uses this font pointer for string
  456.             gadgets (and most other gadget text), menu titles, and
  457.             a few other places. We also need to update the screen's
  458.             BarHeight (this fixes the display of the title-bar, but
  459.             doesn't adjust the drag-gadget attached to it... that
  460.             might make a nice addition to this routine, I'll leave
  461.             that as "an excersize left for the programmer..." :-) */
  462.  
  463. /* ky */    if( SetFont(window->WScreen->BarLayer->rp, newfont) ) {
  464.                 window->WScreen->BarHeight = newfont->tf_YSize + 2;
  465.                 window->WScreen->BarLayer->bounds.MaxY = newfont->tf_YSize + 2;
  466.             }
  467.             CloseFont(oldfont);
  468.         }
  469.     }
  470.  
  471.     /* If the current font is the same font, we can just change the point
  472.           size attribute value.  If its a completely new font, the entire
  473.           attribute pointer is reassigned.  This may not be necessary, but it
  474.           works this way, and I've had trouble with other schemes.  */
  475.  
  476. /* ky */ /*    each Screen structure has a struct TextAttr *Font in it...
  477.             after a fair ammount of investigating, I've found out that
  478.             (for screens that don't specify a font to use in their
  479.             NewScreen struct) this pointer (currently, under 1.3) points
  480.             to... IntuitionBase->SysFont (an INTUITIONPRIVATE field btw :)
  481.             So... it appears that when a new screen is opened, that doesn't
  482.             ask for a specific font in it's NewScreen struct, it uses this
  483.             TextAttr.
  484.                 Dave's code reassigned the entire attribute pointer if it
  485.             was a new font name, this caused the screen to no longer
  486.             point at IntuitionBase->SysFont. What I do is just (effectively)
  487.             change IntuitionBase->SysFont.ta_Name to point to the new font
  488.             name and adjust the ta_YSize.
  489.                 And now for the caveat/feature... any new screens opened
  490.             that don't specify a font will use this new font.  Good if that's
  491.             what you want... Bad if the program doesn't handle it well :) */
  492.  
  493.     if (mode_screen) {
  494.         if (strcmp(window->WScreen->Font->ta_Name,attr->ta_Name) == 0) {
  495.             window->WScreen->Font->ta_YSize = attr->ta_YSize;
  496.             FreeAttr(attr);
  497.         }
  498.         else {
  499. /* ky */    window->WScreen->Font->ta_Name = attr->ta_Name;
  500. /* ky */    window->WScreen->Font->ta_YSize = attr->ta_YSize;
  501.         }
  502.     }
  503.  
  504.     /* The window font is changed via a SetFont() call to the window's
  505.           RastPort, much in the same way that the screen's titling fonts are
  506.           changed.  Additionally, the console device must be reset to force
  507.           the ConUnit to be rebuit, which draws the new font from the
  508.           window.  */
  509.  
  510.     if (mode_window) {
  511.         oldfont = window->RPort->Font;
  512.         if( SetFont(window->RPort,newfont) ) {
  513.  
  514. /* ky */ /* again, we need to adjust the title-bar... */
  515.             window->BorderTop = newfont->tf_YSize + 2 + 1;
  516.             CloseFont(oldfont);
  517.         }
  518.  
  519. /* ky */ /* now comes the ConUnit rebuild (via the printf("\033c"))...
  520.             this (unfortunately) clears the screen, but it also doesn't
  521.             'quite' clean up the top of the window (title-bar area)
  522.             if we are using a new height font.  Since the window will be
  523.             cleared anyway, I've added a RectFill() of my own, to clean
  524.             up the window. */
  525.  
  526.         SetAPen(window->RPort, 0L);
  527.         RectFill( window->RPort, 2L, (long)(window->BorderTop-2),
  528.                                 (long)(window->Width-3),
  529.                                 (long)(window->Height - window->BorderBottom));
  530.         printf("\033c");
  531.         RefreshWindowFrame(window);
  532.     }
  533.  
  534. /* ky */ /* there used to be a 'CloseFont( newfont )' here... but
  535.             since we need it open (cause we are using it) it should
  536.             not be closed */
  537.  
  538.     ShutDown();
  539.     exit(0);
  540. }
  541.